package com.hdu.executor;

import lombok.val;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static java.util.Optional.ofNullable;


public class RuleCalService {

    public static RuleHitResult calculate(Rule rule) {
        val compileComplexExpression = rule.getCompileComplexExpression();
        val runningComplexExpression = calComplexExpression(compileComplexExpression);

        if (runningComplexExpression.isHit()) {
            return RuleHitResult.success(rule, runningComplexExpression);
        } else {
            return RuleHitResult.fail(rule);
        }
    }


    private static RunningComplexExpression calComplexExpression(CompileComplexExpression compileComplexExpression) {
        List<RunningBasicExpression> runningBasicExpressions = new ArrayList<>();
        List<RunningComplexExpression> runningComplexExpressions = new ArrayList<>();

        try {
            val compileComplexExpressions = ofNullable(compileComplexExpression.getCompileComplexExpressions()).orElse(new ArrayList<>());
            val compileBasicExpressions = ofNullable(compileComplexExpression.getCompileBasicExpressions()).orElse(new ArrayList<>());
            val logicOpCode = compileComplexExpression.getLogicOpCode();

            if (compileBasicExpressions.isEmpty() && compileComplexExpressions.isEmpty()) {
                // 没有任何表达式 默认不命中
                return RunningComplexExpression.fail();
            }

            // 处理基本表达式
            if (!compileBasicExpressions.isEmpty()) {
                runningBasicExpressions.addAll(compileBasicExpressions.stream()
                        .map(RuleCalService::calBasicExpression)
                        .filter(RunningBasicExpression::isHit)
                        .collect(Collectors.toList()));
            }

            // 处理复杂表达式
            if (!compileComplexExpressions.isEmpty()) {
                runningComplexExpressions.addAll(compileComplexExpressions.stream()
                        .map(RuleCalService::calComplexExpression)
                        .filter(RunningComplexExpression::isHit)
                        .collect(Collectors.toList()));
            }

            int totalCount = compileBasicExpressions.size() + compileComplexExpressions.size();
            // 综合判断条件
            return judgeExpressionResult(
                    totalCount,
                    runningBasicExpressions,
                    runningComplexExpressions,
                    logicOpCode
            );

        } catch (Exception e) {
            // 可以根据实际情况记录日志或者进行其他异常处理
            e.printStackTrace();
            return RunningComplexExpression.fail();
        }
    }

    private static RunningComplexExpression judgeExpressionResult(int totalCount,
                                                                  List<RunningBasicExpression> runningBasicExpressions,
                                                                  List<RunningComplexExpression> runningComplexExpressions,
                                                                  LogicOpCode logicOpCode) {
        int hitCount = runningBasicExpressions.size() + runningComplexExpressions.size();
        if (hitCount == 0 || (hitCount < totalCount && logicOpCode == LogicOpCode.AND)) {
            return RunningComplexExpression.fail();
        } else {
            return RunningComplexExpression.success(runningBasicExpressions, runningComplexExpressions);
        }
    }


    private static RunningBasicExpression calBasicExpression(CompileBasicExpression compileBasicExpression) {
        val opCode = compileBasicExpression.getOpCode();
        val paramName = compileBasicExpression.getParamName();
        val thresholdValue = compileBasicExpression.getThresholdValue();

        // 查询参数值
        val paramValue = ParamQueryService.queryParamValue(paramName);

        // 比较
        boolean hit = CompareHelper.compare(opCode, paramValue, thresholdValue);

        val runningBasicExpression = new RunningBasicExpression();
        runningBasicExpression.setHit(hit);
        runningBasicExpression.setParamValue(paramValue);
        runningBasicExpression.setThresholdValue(thresholdValue);
        runningBasicExpression.setOpCode(opCode);
        runningBasicExpression.setParamName(paramName);

        return runningBasicExpression;
    }


}
